/***************************************************************************
 *   Copyright (C) YEAR~YEAR by Your Name                                  *
 *   your-email@address.com                                                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
 ***************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <fcitx/ime.h>
#include <fcitx-config/fcitx-config.h>
#include <fcitx-config/xdg.h>
#include <fcitx-utils/log.h>
#include <fcitx-utils/utils.h>
#include <fcitx-utils/utf8.h>
#include <fcitx/instance.h>
#include <fcitx/context.h>
#include <fcitx/module.h>
#include <fcitx/hook.h>
#include <libintl.h>
#include <fcitx/keys.h>
#include "config.h"
#include "freewubi-internal.h"
#include "freedict.h"
#include "freespecial.h"
#include "freeinterface.h"
#include "virtual_keyboard.h"
#define MAX_TABLE_INPUT 50
#define SOUND_FILE_PATH "/usr/share/freewb/sound"
#define UBUNTU_KQLIN "ukui"
#define DEEPIN ""
static const char *soundData[SOUND_NUM] =
{
    "letter.wav",//SOUND_LETTER
    "enter.wav",//SOUND_ENTER
    "back.wav",//SOUND_BACK
    "recode.wav",//SOUND_RECODE
    "space.wav",//SOUND_SAPCE
    "empty.wav"//SOUND_EMPTY
};
#define STR_ADD_PHRASE "aa."
#define STR_DELETE_PHRASE "dd."
#define STR_SWITCH_UNCOMMON "ss."
#define STR_RECODE_PROOF "tt."
#define STR_CHTTRANS "jj."
#define STR_REVERSE_CHECK "ff."
#define STR_HIDE_TOOLBAR "hh."
#define STR_SWITCH_KEYBORD "kk."
#define STR_SWITCH_CHAR_SET "mm."
#define STR_OPEN_CONFIG "oo."
#define STR_VERSION "vv."
#define STR_HIDE_CANDWIN "cc."
#define STR_PROFEESINAL "pp."
#define STR_QUICK_TABLE "qq."
#define STR_USER_TABLE "uu."
#define STR_WUBI_TABLE "uw."
#define STR_PINYIN_TABLE "up."
#define STR_CONF_DIR "dos."
static void TableMetaDataFree(TableMetaData *table);
static void *FcitxfreewubiCreate(FcitxInstance *instance);
static void FcitxfreewubiDestroy(void *arg);
static INPUT_RETURN_VALUE FreeWubiGetCandWord(void* arg, FcitxCandidateWord* candWord);
static INPUT_RETURN_VALUE FreeWubiGetCandWords(void* arg);
static INPUT_RETURN_VALUE DoFreeWubiReleaseIntput(void* arg, FcitxKeySym sym, unsigned int state);
static void FcitxfreewubiClose( void* arg, FcitxIMCloseEventType);
static FcitxHotkey  FreewbCTRL_ENTER[2];
static FcitxHotkey  FreewbCAPS_LOCK[2];
static void InternalInit(Fcitxfreewubi* fwb);
static int digitalNumberTrans(FcitxKeySym sym);
static void playSound(SoundType sType);
#ifdef __cplusplus
extern "C" {
#endif
// CONFIG_DEFINE_LOAD_AND_SAVE(freewubi, FcitxfreewubiConfig, "fcitx-freewubi");

CONFIG_DESC_DEFINE(GetFreewubiGlobalConfigDesc, "fcitx-freewubi.desc")
FCITX_DEFINE_PLUGIN(fcitx_freewubi, ime, FcitxIMClass) = {
    FcitxfreewubiCreate,
    FcitxfreewubiDestroy
};

#ifdef __cplusplus
}
#endif
boolean isFreewbRuning(){
    char lock_file[] = "/tmp/fcitx-freewb.pid";
    struct flock fl;
    int fd;
    if ( access(lock_file, F_OK) != -1 )
    {
        fd = open( lock_file, O_RDWR );
        if ( fd < 0 )
        {
            printf( "can not open %s :%s\n", lock_file, strerror(errno) );
            fflush( stdout );
        }
        else
        {
            fl.l_type = F_WRLCK;
            fl.l_start = 0;
            fl.l_whence = SEEK_SET;
            fl.l_len = 0;

            if ( fcntl(fd, F_GETLK, &fl) < 0 )
            {
                printf( "can not get lock status: %s :%s\n", lock_file, strerror(errno) );
                fflush( stdout );
            }
            else
            {
                if( fl.l_type == F_WRLCK )
                {
                    fflush( stdout );
                    return true;
                }
            }
        }
    }
    else
    {
        printf( "%s isn't exist!\n", lock_file );
        fflush( stdout );
        return false;
    }  
    return false;
}

void run_freewb_pannel()
{
    char panelBin[512] = {0};
    strcpy(panelBin,"/usr/bin/freewb.sh");
    char lock_file[] = "/tmp/fcitx-freewb.pid";
    struct flock fl;
    int fd;

    if ( access(lock_file, F_OK) != -1 )
    {
        fd = open( lock_file, O_RDWR );
        if ( fd < 0 )
        {
            printf( "can not open %s :%s\n", lock_file, strerror(errno) );
            fflush( stdout );
        }
        else
        {
            fl.l_type = F_WRLCK;
            fl.l_start = 0;
            fl.l_whence = SEEK_SET;
            fl.l_len = 0;

            if ( fcntl(fd, F_GETLK, &fl) < 0 )
            {
                printf( "can not get lock status: %s :%s\n", lock_file, strerror(errno) );
                fflush( stdout );
            }
            else
            {
                if( fl.l_type == F_WRLCK )
                {
                    fflush( stdout );
                    return;
                }
            }
        }
    }
    else
    {
        printf( "%s isn't exist!\n", lock_file );
        fflush( stdout );
    }

//     printf( "The freewb panel doesn't seem to be running, now try to execute: %s\n", panelBin );
    fflush( stdout );
    system( panelBin );
}

boolean FreewubiInit(void *arg)
{
//     printf( "fffffffffffffffffffffffffffffffff FreewubiInit\n" );
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    run_freewb_pannel();//防止面板没有启动
    if(!fwb->table){
        fwb->table = fcitx_utils_new(TableMetaData);
        fwb->table->owner = fwb;
        LoadTableDict(fwb->table);
        fwb->table->tableType = FREE_WUBI;
    }

    if(fwb->bNotFirstStart){
//			fwb->bSwichImSeccess =
		switchImState(fwb, IM_INTO_FREEWB);
    }

    switchFreeIm(fwb,fwb->table->tableType);
    fwb->bIsAutoEnglish = false;

    return true;
}
void FreewubiResetStatus(void* arg)
{
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    FcitxInputState *input = FcitxInstanceGetInputState(fwb->owner);
    fwb->bIsTableAddPhrase = false;
    fwb->bIsTableDelPhrase = false;
    fwb->bIsTableAdjustOrder = false;
    fwb->bIsTempEnglish = false;
    fwb->bIsTableAddPhraseByClip = false;
//     fwb->bIsAutoEnglish = false;
    FcitxInputStateSetIsDoInputOnly(input, false);
         
}

boolean TableCheckNoMatch(TableMetaData* table, const char* code)
{
//     FcitxInstance *instance = table->owner->owner;
//     FcitxInputState *input = FcitxInstanceGetInputState(instance);
//     FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
    return (/*FcitxCandidateWordGetListSize(candList) == 0&&*/TableFindFirstMatchCode(table, code, false, false) == -1);
}
void TableAddRemindCandWord(RECORD * record, TABLECANDWORD* tableCandWord)
{
    tableCandWord->flag = CT_REMIND;
    tableCandWord->candWord.record = record;
}
/*
 * 获取联想候选字列表
 */
#if 1
INPUT_RETURN_VALUE TableGetRemindCandWords(TableMetaData* table)
{
    Fcitxfreewubi* fwb = table->owner;
    int             iLength;
    RECORD         *tableRemind = NULL;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxCandidateWordList *cand_list = FcitxInputStateGetCandidateList(input);
    if (!fwb->strTableRemindSource[0])
        return IRV_TO_PROCESS;

    FcitxInputStateGetRawInputBuffer(input)[0] = '\0';
    FcitxInputStateSetRawInputBufferSize(input, 0);
    FcitxCandidateWordReset(cand_list);

    iLength = fcitx_utf8_strlen(fwb->strTableRemindSource);
    tableRemind = table->WubiDict->recordHead->next;

    while (tableRemind != table->WubiDict->recordHead) {

        if (((iLength + 1) <= fcitx_utf8_strlen(tableRemind->strHZ))) {
            if (!fcitx_utf8_strncmp(tableRemind->strHZ,
                                    fwb->strTableRemindSource, iLength) &&
                fcitx_utf8_get_nth_char(tableRemind->strHZ, iLength)) {
                TABLECANDWORD *tableCandWord = fcitx_utils_new(TABLECANDWORD);
                TableAddRemindCandWord(tableRemind, tableCandWord);
                FcitxCandidateWord candWord;
                candWord.callback = FreeWubiGetCandWord;
                candWord.owner = fwb;
                candWord.priv = tableCandWord;
                candWord.strExtra = NULL;
                candWord.strWord = strdup(tableCandWord->candWord.record->strHZ );
                candWord.wordType = MSG_OTHER;
                FcitxCandidateWordAppend(cand_list, &candWord);
            }
        }
        tableRemind = tableRemind->next;
    }

    FcitxInstanceCleanInputWindowUp(instance);
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input),
                                         MSG_INPUT, _("#词组联想:"));
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input),
                                         MSG_INPUT, fwb->strTableRemindSource);  
    FcitxInputStateSetShowCursor(input,true);
    FcitxInputStateSetCursorPos(input, strlen("#词组联想:")+strlen(fwb->strTableRemindSource));
    int count = FcitxCandidateWordPageCount(cand_list);
    FcitxInputStateSetIsInRemind(input, count);
    if (count) {
        return IRV_DISPLAY_CANDWORDS;
    } else {
        return IRV_CLEAN;
    }
}
INPUT_RETURN_VALUE TableGetRemindCandWord(void* arg, TABLECANDWORD* tableCandWord)
{
    TableMetaData* table = (TableMetaData*) arg;
    Fcitxfreewubi* fwb = table->owner;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);

//     tableCandWord->candWord.record->iHit++;
    strcpy(fwb->strTableRemindSource, tableCandWord->candWord.record->strHZ + strlen(fwb->strTableRemindSource));
    TableGetRemindCandWords(table);

    strcpy(FcitxInputStateGetOutputString(input), fwb->strTableRemindSource);
    return IRV_COMMIT_STRING_REMIND;
}
#endif
/*
 * 第二个参数表示是否进入联想模式，实现自动上屏功能时，不能使用联想模式
 */
INPUT_RETURN_VALUE _TableGetCandWord(TableMetaData* table, TABLECANDWORD* tableCandWord, boolean _bRemind)
{
    char           *pCandWord = NULL;
    Fcitxfreewubi* fwb = table->owner;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxInputStateSetIsInRemind(input, false);
    switch (tableCandWord->flag) {
    case CT_NORMAL:
        pCandWord = tableCandWord->candWord.record->strHZ;
        if(!fwb->pLastCommitRecord)
            fwb->pLastCommitRecord = fcitx_utils_new(RECORD);
        fwb->pLastCommitRecord->owner = tableCandWord->candWord.record->owner;
        fwb->pLastCommitRecord->strCode = tableCandWord->candWord.record->strCode;
        fwb->pLastCommitRecord->strHZ = tableCandWord->candWord.record->strHZ;   
        fwb->pLastCommitRecord->type = tableCandWord->candWord.record->type;
        break;
    case CT_REMIND: 
        strcpy(fwb->strTableRemindSource, tableCandWord->candWord.record->strHZ + strlen(fwb->strTableRemindSource));
        strcpy(FcitxInputStateGetOutputString(input), fwb->strTableRemindSource);
        INPUT_RETURN_VALUE retVal = TableGetRemindCandWords(table);
        if (retVal == IRV_DISPLAY_CANDWORDS)
            return IRV_COMMIT_STRING_REMIND;
        else
            return IRV_COMMIT_STRING;
        if(fwb->pLastCommitRecord){
            free(fwb->pLastCommitRecord);
            fwb->pLastCommitRecord = NULL;
        }
        break;
    case CT_REPEATE:
        pCandWord = fwb->pLastCommitRecord->strHZ;
        if(!fwb->pLastCommitRecord)
            fwb->pLastCommitRecord = fcitx_utils_new(RECORD);
        fwb->pLastCommitRecord->owner = tableCandWord->candWord.record->owner;
        fwb->pLastCommitRecord->strCode = tableCandWord->candWord.record->strCode;
        fwb->pLastCommitRecord->strHZ = tableCandWord->candWord.record->strHZ;  
        fwb->pLastCommitRecord->type = tableCandWord->candWord.record->type;
        if(!fwb->pLastCommitRecord->strCode[0]){
            FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),fwb->pLastCommitRecord->strHZ);
            FcitxInstanceResetInput(instance);
            FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Left, FcitxKeyState_None);
            return IRV_CLEAN;
        }        
        break;
    case CT_AUTOPHRASE:
        pCandWord = tableCandWord->candWord.autoPhrase->strHZ;
        tableCandWord->candWord.autoPhrase->iSelected = true;
        if(fwb->config.iAutoPhraseOpt == 2){
            addUsrParse(fwb,1,tableCandWord->candWord.autoPhrase->strHZ,tableCandWord->candWord.autoPhrase->strCode);
        }
        if(!fwb->pLastCommitRecord)
            fwb->pLastCommitRecord = fcitx_utils_new(RECORD);
        fwb->pLastCommitRecord->owner = table->WubiDict;
        fwb->pLastCommitRecord->strCode = tableCandWord->candWord.autoPhrase->strCode;
        fwb->pLastCommitRecord->strHZ = tableCandWord->candWord.autoPhrase->strHZ;   
        break;
    case CT_QUICK:
        pCandWord = tableCandWord->candWord.qucikPhrase->value;
        if(!fwb->pLastCommitRecord)
            fwb->pLastCommitRecord = fcitx_utils_new(RECORD);
        fwb->pLastCommitRecord->owner = table->WubiDict;
        fwb->pLastCommitRecord->strCode = malloc(sizeof(char) * 2);
        fwb->pLastCommitRecord->strCode[0] = tableCandWord->candWord.qucikPhrase->key;
        fwb->pLastCommitRecord->strCode[1] = '\0';
        fwb->pLastCommitRecord->strHZ = tableCandWord->candWord.qucikPhrase->value;  
        if(!fwb->pLastCommitRecord->strCode[0]){
            FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),fwb->pLastCommitRecord->strHZ);
            FcitxInstanceResetInput(instance);
            fwb->bNeedMoveCur = true;
           // FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Left, FcitxKeyState_None);
            return IRV_CLEAN;
        }
        break;        
    }
    if (fwb->config.bPhraseRemind) {
        strcpy(fwb->strTableRemindSource, pCandWord);
        strcpy(FcitxInputStateGetOutputString(input), pCandWord);
        INPUT_RETURN_VALUE retVal = TableGetRemindCandWords(table);
        if (retVal == IRV_DISPLAY_CANDWORDS)
            return IRV_COMMIT_STRING_REMIND;
    } 
    else {
        FcitxInstanceCleanInputWindow(instance);
    }
    boolean needFree = false;
    if(tableCandWord->candWord.record && tableCandWord->candWord.record->type == RECORDTYPE_CONSTRUCT){
        pCandWord  = matchTime(pCandWord);
        needFree = true;
    }
    if(fwb->config.bIsTraditional && tableCandWord->candWord.record && tableCandWord->candWord.record->type!=RECORDTYPE_S2T){
        char *strTemp = s2tConvers(table,pCandWord);
        if(needFree)
            free(pCandWord);
        pCandWord = strTemp;
        needFree = true;
    }
    strcpy(FcitxInputStateGetOutputString(input), pCandWord);
    if(needFree)
        free(pCandWord);
    return IRV_COMMIT_STRING;
}
void TableAddCandWord(RECORD * record, TABLECANDWORD* tableCandWord)
{
    tableCandWord->flag = CT_NORMAL;
    tableCandWord->candWord.record = record;
}
void TableAddAutoCandWord(AUTOPHRASE* autoPhrase, TABLECANDWORD* tableCandWord)
{
    tableCandWord->flag = CT_AUTOPHRASE;
    tableCandWord->candWord.autoPhrase = autoPhrase;
}
INPUT_RETURN_VALUE DoFreeWubiReleaseIntput(void* arg, FcitxKeySym sym, unsigned int state)
{
//         printf("key:%c\n",sym);
//     printf("state:%d\n",state);
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
     FcitxInstance *instance = fwb->owner;
//     FcitxInputState *input = FcitxInstanceGetInputState(instance);
//     int puncNumber = -1;    
//     if(state == FcitxKeyState_None)
//         puncNumber = isPuncKey(sym);
//     if(!fwb->bIsTempEnglish&&-1!=puncNumber&&fwb->config.bUseSmartPunc){                    
//         FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Left, FcitxKeyState_None);
//         return IRV_TO_PROCESS;
//     }  
    if(fwb->bNeedMoveCur)
        FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Left, FcitxKeyState_None);
    fwb->bNeedMoveCur = false;
    return IRV_TO_PROCESS;
}
void FcitxfreewubiClose( void* arg, FcitxIMCloseEventType event_type){
//	printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaa free close\n");
	Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
	FcitxInstance *instance = fwb->owner;
	FcitxInputState *input = FcitxInstanceGetInputState(instance);
	if(event_type == CET_SwitchIM){
		switchImState(fwb, IM_CLOSE_FREEWB);
//		printf("freewb close\n");
	}
	else if(event_type == CET_ChangeByInactivate){
		switchImState(fwb, IM_TO_ENGLISH);
//		printf("CET_ChangeByInactivate close\n");
		char* strCodeInput = FcitxInputStateGetRawInputBuffer(input);
		FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),strCodeInput);
		FcitxInstanceResetInput(instance);
	}
}
INPUT_RETURN_VALUE DoFreeWubiIntput(void* arg, FcitxKeySym sym, unsigned int state)
{
//     printf("key:%d\n",sym);
//     printf("state:%d\n",state);
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;

    if(!fwb->bNotFirstStart){ //如果是第一次启动
//    	fwb->bSwichImSeccess =
    	switchImState(fwb, IM_INTO_FREEWB);
    	fwb->bNotFirstStart = true;
    }
//    if(!fwb->bSwichImSeccess){
//    	fwb->bSwichImSeccess = switchImState(fwb, IM_INTO_FREEWB);
//    }
    TableMetaData *table = fwb->table;
    INPUT_RETURN_VALUE retVal;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxProfile* profile = FcitxInstanceGetProfile(instance);
    char* strCodeInput = FcitxInputStateGetRawInputBuffer(input);
//     FcitxGlobalConfig *fcitxConfig  = FcitxInstanceGetGlobalConfig(instance);
    FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
    char *output_str = FcitxInputStateGetOutputString(input);
    int puncNumber = -1;
    FcitxCandidateWordSetChooseAndModifier(candList, DIGIT_STR_CHOOSE,FcitxKeyState_None);
    FcitxInstanceSetContext(fwb->owner, CONTEXT_ALTERNATIVE_PREVPAGE_KEY,
                                fwb->config.hkAlternativePrevPage);
    FcitxInstanceSetContext(fwb->owner, CONTEXT_ALTERNATIVE_NEXTPAGE_KEY,
                                fwb->config.hkAlternativeNextPage);
    if(fwb->bisDelNumber){
        if(state == FcitxKeyState_None && sym>='0' && sym <='9'){
            int index = sym - '1';
            if(sym == '0'){
                index = 9;
            }
            if(index<0||index>FcitxCandidateWordGetCurrentWindowSize(candList)-1)
                return IRV_DO_NOTHING;
            else{
                TABLECANDWORD* tableCandWord = FcitxCandidateWordGetByIndex(candList,index)->priv;
                if(tableCandWord->flag == CT_NORMAL){
                    RECORD* recTemp =tableCandWord->candWord.record;
                    fwb->bIsTableDelPhrase = false;
                    FcitxInputStateSetIsDoInputOnly(input, false);   
                    if(recTemp)
                        deleteUsrParse(fwb,1,recTemp->strHZ,recTemp->strCode);            
                    return FreeWubiGetCandWords(fwb);
                }
            }      
        }
        else
            fwb->bisDelNumber = false;
    }
    
    if(fwb->config.iKeyboardMode!=-1){
        if(FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE))
            closeVkBoard(fwb);
        if(FcitxHotkeyIsHotKeySimple(sym,state)){
            if(fwb->config.iKeyboardMode){
                char *matchStr = matchVkBoard(sym,fwb->config.iKeyboardMode);
                if(matchStr){
                    FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),matchStr);
                    FcitxInstanceResetInput(instance);
                    return IRV_CLEAN;
                }
            }
        }
    }
    
    if(fwb->bIsAutoEnglish){
        if(FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)){
            profile->bUseWidePunc = fwb->bUseWidePunc;
            profile->bUseFullWidthChar = fwb->bUseFullWidthChar;
            setCharWidth(fwb,!profile->bUseFullWidthChar,!profile->bUseWidePunc);
            fwb->bIsAutoEnglish = false;
            switchFreeIm(fwb,table->tableType);
            return IRV_TO_PROCESS;
        }
        else if(FcitxHotkeyIsHotKeySimple(sym,state)){
            profile->bUseWidePunc = false;
            profile->bUseFullWidthChar = false;
            size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
            strCodeInput[raw_size] = (char)sym;
            raw_size++;
            strCodeInput[raw_size] = '\0';
            FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),strCodeInput);
            FcitxInstanceResetInput(instance);
            return IRV_CLEAN;      
        }
        else
            return IRV_TO_PROCESS;
    }      
    else if(state == FcitxKeyState_None){
        size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
        strCodeInput[raw_size] = (char)sym;
        raw_size++;
        strCodeInput[raw_size] = '\0';
        FcitxInputStateSetRawInputBufferSize(input, raw_size); 
        if(isAutoEngStr(table,strCodeInput)){
            fwb->bUseWidePunc = profile->bUseWidePunc;
            fwb->bUseFullWidthChar = profile->bUseFullWidthChar;
            profile->bUseWidePunc = false;
            profile->bUseFullWidthChar = false;
            setCharWidth(fwb,!profile->bUseFullWidthChar,!profile->bUseWidePunc);
            FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),strCodeInput);
            FcitxInstanceResetInput(instance);
            fwb->bIsAutoEnglish = true;
            switchFreeIm(fwb,3);
            return IRV_CLEAN;               
        }
        else{
            strCodeInput[--raw_size] = '\0';
            FcitxInputStateSetRawInputBufferSize(input, raw_size);            
        }
    }
    if( FcitxHotkeyIsHotKeyUAZ(sym,state)&&!fwb->bIsAutoEnglish && !fwb->bIsTableAddPhrase && !fwb->bIsTableDelPhrase && !fwb->bIsTempEnglish){
        if (FcitxCandidateWordPageCount(candList)) {
            FcitxCandidateWord* candWord = FcitxCandidateWordGetCurrentWindow(candList);
            if (candWord->owner == fwb) {
                INPUT_RETURN_VALUE ret = FreeWubiGetCandWord(fwb, candWord);
                if (ret & IRV_FLAG_PENDING_COMMIT_STRING) {
                    FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), output_str);
                    FcitxInstanceResetInput(instance);
                }
            }
        }
        if(fwb->config.bShiftCommit){
            char comStr[2] = {sym,0};
            FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), comStr);
            return IRV_CLEAN;
        }
        else{
            return IRV_TO_PROCESS;
        }
    }   
    if(state != FcitxKeyState_None && fwb->config.bDisableHk)
        return IRV_TO_PROCESS;
    if(FcitxHotkeyIsHotKey(sym,state,fwb->config.hkSwitchFreeim)){
        table->tableType  = (table->tableType+1)%3;
        switchFreeIm(fwb,table->tableType);
        return IRV_DO_NOTHING;
    }
    retVal = IRV_DO_NOTHING;
    if((sym==fwb->config.QuickInputKey && state==FcitxKeyState_None && !FcitxInputStateGetRawInputBufferSize(input))){
        size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
        strCodeInput[raw_size] = (char)sym;
        raw_size++;
        strCodeInput[raw_size] = '\0';
        FcitxInputStateSetRawInputBufferSize(input, raw_size);         
        return IRV_DISPLAY_CANDWORDS;
    }
    else if(fwb->config.QuickInputKey && strCodeInput[0] == fwb->config.QuickInputKey){
        if ((FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)||(sym==fwb->config.QuickInputKey&& state==FcitxKeyState_None))
            &&FcitxCandidateWordPageCount(candList) != 0) {
            if(fwb->config.bInputVoice)
                playSound(SOUND_SAPCE);
            return FcitxCandidateWordChooseByIndex(candList, 0);
        } 
        if(FcitxHotkeyIsHotKeySimple(sym,state)){
            size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
            strCodeInput[raw_size] = (char)sym;
            raw_size++;
            strCodeInput[raw_size] = '\0';
            FcitxInputStateSetRawInputBufferSize(input, raw_size);  
            return IRV_DISPLAY_CANDWORDS;  
        }        
    }
    if(state == FcitxKeyState_None)
        puncNumber = isPuncKey(sym);
    if(!fwb->bIsTempEnglish&&-1!=puncNumber&&fwb->config.bUseSmartPunc&&!(FcitxCandidateWordPageCount(candList)&&FcitxHotkeyIsHotKey(sym, state, fwb->config.hkThirdRecode))){
        if (FcitxCandidateWordPageCount(candList)) {
            retVal = FcitxCandidateWordChooseByIndex(candList, 0);
             if(retVal == IRV_TO_PROCESS)
                retVal = IRV_CLEAN;
        }
        if(IRV_DO_NOTHING == retVal)
            output_str[0] = '\0';                     
        matchPunc(output_str,puncNumber,profile->bUseWidePunc);
        FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),output_str);
        FcitxInstanceResetInput(instance);
        fwb->bNeedMoveCur = true;
//         FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_Left, FcitxKeyState_None);
        return IRV_CLEAN;
    }  
    if (state == FcitxKeyState_None && !fwb->bIsTempEnglish && !fwb->bIsAutoEnglish &&
        (IsInputKey(table, sym)|| (table->tableType!=FREE_PINYIN&&(IsUncommonKey(table,sym,state) 
        ||(strCodeInput[0]==fwb->config.unCommonKey&&'/'==sym))))) {
        if(fwb->config.bInputVoice)
            playSound(SOUND_LETTER);
        if (FcitxInputStateGetIsInRemind(input))
            FcitxCandidateWordReset(candList);
        FcitxInputStateSetIsInRemind(input, false);
        /* it's not in special state */
        if (!fwb->bIsTableAddPhrase && !fwb->bIsTableDelPhrase &&
            !fwb->bIsTableAdjustOrder) {
            if(IsUncommonKey(table,sym,state)&&FcitxInputStateGetRawInputBufferSize(input)==1&&strCodeInput[0]==fwb->config.unCommonKey){
                return FcitxCandidateWordChooseByIndex(candList, 0);
            }
            size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
            strCodeInput[raw_size] = (char)sym;
            raw_size++;
            strCodeInput[raw_size] = '\0';
            FcitxInputStateSetRawInputBufferSize(input, raw_size); 
            boolean bhasMatch = !TableCheckNoMatch(table, FcitxInputStateGetRawInputBuffer(input));
            if(!strncmp(strCodeInput,"zz",2))
                FcitxCandidateWordSetPageSize(candList, 10);
            else
                FcitxCandidateWordSetPageSize(candList, fwb->config.iCandidateWordNumber);
            //是否超过五笔字符长度
            //是否超过拼音或生僻字字符长度
            if ((table->tableType!=FREE_PINYIN && raw_size <= table->WubiDict->iCodeLength)||bhasMatch)
            {
                
                retVal = FreeWubiGetCandWords(fwb); 
                if(fwb->config.bRecodeVoice){
                    if(table->tableType!=FREE_PINYIN && raw_size == table->WubiDict->iCodeLength){
                        if(FcitxCandidateWordGetByIndex(candList,1)){
                            TABLECANDWORD* tableCandWord2 = FcitxCandidateWordGetByIndex(candList,1)->priv;
                            if(tableCandWord2->flag == CT_NORMAL &&strcmp(strCodeInput,tableCandWord2->candWord.record->strCode)==0
                                &&tableCandWord2->candWord.record->owner==table->WubiDict){
                                playSound(SOUND_RECODE);
                            }
                        }
                        if(!bhasMatch)
                            playSound(SOUND_EMPTY);
                    }
                }
                retVal = IRV_DISPLAY_CANDWORDS;
            }
            else {
                strCodeInput[--raw_size] = '\0';
                retVal = IRV_DISPLAY_CANDWORDS;
                char strReCodeProof[50] = {0};
                if (FcitxCandidateWordPageCount(candList)) {
                    FcitxCandidateWord* candWord = FcitxCandidateWordGetCurrentWindow(candList);
                    if (candWord->owner == fwb) {
                        TABLECANDWORD* tableCandWord = candWord->priv;
                        if (tableCandWord->candWord.record &&(!strcmp(tableCandWord->candWord.record->strCode,strCodeInput)||
                            (strCodeInput[0]==fwb->config.unCommonKey &&!strcmp(tableCandWord->candWord.record->strCode,strCodeInput+1)))) {
                            if(fwb->config.bRecodeProof&&FcitxCandidateWordGetByIndex(candList,1)){
                                TABLECANDWORD* tableCandWord2 = FcitxCandidateWordGetByIndex(candList,1)->priv;
                                if(tableCandWord2->flag == CT_NORMAL &&strcmp(strCodeInput,tableCandWord2->candWord.record->strCode)==0){
                                    strcat(strReCodeProof,"【");
                                    strcat(strReCodeProof,FcitxCandidateWordGetByIndex(candList,1)->strWord);
                                    strcat(strReCodeProof,"】");
                                }
                            }
                            INPUT_RETURN_VALUE ret = FreeWubiGetCandWord(fwb, candWord);
                            if (ret & IRV_FLAG_PENDING_COMMIT_STRING) {
                                FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), output_str);
                                strCodeInput[0] = sym;
                                strCodeInput[1] = '\0';
                                FcitxInputStateSetRawInputBufferSize(input, 1);
                            }
                        }
                        else{
                            strCodeInput[raw_size] = (char)sym;
                            raw_size++;
                            strCodeInput[raw_size] = '\0';  
                            FcitxInputStateSetRawInputBufferSize(input, raw_size);
                            if(fwb->config.bRecodeVoice)
                                playSound(SOUND_EMPTY);
                        }
                    }
                }
                else{
                    if(fwb->config.bRecodeProof){
                        strcat(strReCodeProof,"【");
                        strcat(strReCodeProof,strCodeInput);
                        strcat(strReCodeProof,"】");    
                    }
                    FcitxInputStateSetRawInputBufferSize(input, 1);
                    strCodeInput[0] = sym;
                    strCodeInput[1] = '\0';                            
                    FcitxInputStateSetIsInRemind(input, false);
                }
                if(fwb->config.bRecodeProof)
                    FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), strReCodeProof);
            }      
        }
    } else {
        if(FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)&&fwb->config.bInputVoice)
            playSound(SOUND_ENTER);
        if(sym == fwb->config.tempEnglishKey && state==FcitxKeyState_None && !FcitxInputStateGetRawInputBufferSize(input) && !fwb->bIsTempEnglish){
            fwb->bIsTempEnglish = true;
            size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
            strCodeInput[raw_size] = (char)sym;
            raw_size++;
            strCodeInput[raw_size] = '\0';
            FcitxInputStateSetRawInputBufferSize(input, raw_size); 
            return IRV_DISPLAY_CANDWORDS;      
        }     
        else if(fwb->bIsTempEnglish){
            if (FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)) {
                if(fwb->config.bInputVoice)
                    playSound(SOUND_BACK);
                if (!FcitxInputStateGetRawInputBufferSize(input)) {
                    FcitxInputStateSetIsInRemind(input, false);
                    return IRV_DONOT_PROCESS_CLEAN;
                }
                FcitxInputStateSetRawInputBufferSize(input, FcitxInputStateGetRawInputBufferSize(input) - 1);
                strCodeInput[FcitxInputStateGetRawInputBufferSize(input)] = '\0';
                if (FcitxInputStateGetRawInputBufferSize(input))
                    return IRV_DISPLAY_CANDWORDS;
                else
                    return IRV_CLEAN;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)&&FcitxCandidateWordPageCount(candList) != 0) {
                if(fwb->config.bInputVoice)
                    playSound(SOUND_SAPCE);
                fwb->bIsTempEnglish = false;
                return FcitxCandidateWordChooseByIndex(candList, 0);
                
            }
            else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSecondRecode)&&FcitxCandidateWordGetByIndex(candList,1)){
                fwb->bIsTempEnglish = false;
                return FcitxCandidateWordChooseByIndex(candList, 1);
                                 
            }else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkThirdRecode)&&FcitxCandidateWordGetByIndex(candList,2)){
                fwb->bIsTempEnglish = false;
                return FcitxCandidateWordChooseByIndex(candList, 2);
                
            }            
            else if(FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)){
                if(fwb->config.bInputVoice)
                    playSound(SOUND_ENTER);
                
                FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), strCodeInput+1);
                fwb->bIsTempEnglish = false;
                return IRV_CLEAN;
            }
            else if(FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE)){
                fwb->bIsTempEnglish = false;
                return IRV_CLEAN;
            }  
            else if(sym == fwb->config.tempEnglishKey && state==FcitxKeyState_None && FcitxInputStateGetRawInputBufferSize(input)==1){
                if(fwb->config.bInputVoice)
                    playSound(SOUND_SAPCE);
                retVal = FcitxCandidateWordChooseByIndex(candList, 0);
                fwb->bIsTempEnglish = false;                
            }
            else if(FcitxHotkeyIsHotKeySimple(sym,state)){
                size_t raw_size = FcitxInputStateGetRawInputBufferSize(input);
                strCodeInput[raw_size] = (char)sym;
                raw_size++;
                strCodeInput[raw_size] = '\0';
                FcitxInputStateSetRawInputBufferSize(input, raw_size); 
                retVal = IRV_DISPLAY_CANDWORDS;
            }
        }        
        if (fwb->bIsTableAddPhrase) {
            if (FcitxHotkeyIsHotKey(sym, state, FCITX_LEFT)) {
                if(fwb->bIsTableAddPhraseByClip){
                    char* str = getClipboard(fwb);
                    int strLen=fcitx_utf8_strlen(str);                    
                    if(fwb->iTableNewPhraseHZCount < strLen && fwb->iTableNewPhraseHZCount < PHRASE_MAX_LENGTH){
                        fwb->iTableNewPhraseHZCount++;
                        int i;
                        char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                        memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                        char strCode[5];
                        memset(strCode,0,5);
                        for (i = fwb->iTableNewPhraseHZCount; i >= 0&&i<strLen; i++){
                            str = str + fcitx_utf8_char_len(str);
                        }  
                        strcpy(strHZ,str);
                        if(TableCalPhraseCode(table->WubiDict, strHZ,strCode))
                            addUsrParse(fwb,0,strHZ,strCode);                        
                    }
                    else
                        playSound(SOUND_RECODE);
                }
                else if (!fwb->bIsTableAddPhraseByClip &&fwb->iTableNewPhraseHZCount < table->WubiDict->iHZLastInputCount && fwb->iTableNewPhraseHZCount < PHRASE_MAX_LENGTH) {
                    fwb->iTableNewPhraseHZCount++;
                    int i;
                    char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                    memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                    char strCode[5];
                    memset(strCode,0,5);
                    for (i = table->WubiDict->iHZLastInputCount-fwb->iTableNewPhraseHZCount; i >= 0&&i<table->WubiDict->iHZLastInputCount; i++){
                        strcat(strHZ, table->WubiDict->hzLastInput[i%PHRASE_MAX_LENGTH].strHZ);
                    }      
                    if(TableCalPhraseCode(table->WubiDict, strHZ,strCode))
                        addUsrParse(fwb,0,strHZ,strCode);
                }
                else
                    playSound(SOUND_RECODE);
                return IRV_DO_NOTHING;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_RIGHT)) {
                if (fwb->iTableNewPhraseHZCount > 2) {
                    fwb->iTableNewPhraseHZCount--;
                    int i;
                    char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                    memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                    char strCode[5];
                    memset(strCode,0,5);
                    if(fwb->bIsTableAddPhraseByClip){
                        char* str = getClipboard(fwb);
                        int strLen=fcitx_utf8_strlen(str);
                        for (i = fwb->iTableNewPhraseHZCount; i >= 0&&i<strLen; i++){
                            str = str + fcitx_utf8_char_len(str);
                        }  
                        strcpy(strHZ,str);                        
                    }
                    else{
                        for (i = table->WubiDict->iHZLastInputCount-fwb->iTableNewPhraseHZCount; i >= 0&&i<table->WubiDict->iHZLastInputCount; i++){
                            strcat(strHZ, table->WubiDict->hzLastInput[i%PHRASE_MAX_LENGTH].strHZ);
                        }   
                    }
                    if(TableCalPhraseCode(table->WubiDict, strHZ,strCode))
                        addUsrParse(fwb,0,strHZ,strCode);
                }
                else
                    playSound(SOUND_RECODE);
                return IRV_DO_NOTHING;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)) {
                fwb->bIsTableAddPhrase = false;
                fwb->bIsTableAddPhraseByClip = false;
                FcitxInputStateSetIsDoInputOnly(input, false);
                int i;
                char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                char strCode[5];
                memset(strCode,0,5);
                if(fwb->bIsTableAddPhraseByClip){
                    char* str = getClipboard(fwb);
                    int strLen=fcitx_utf8_strlen(str);
                    for (i = fwb->iTableNewPhraseHZCount; i >= 0&&i<strLen; i++){
                        str = str + fcitx_utf8_char_len(str);
                    }  
                    strcpy(strHZ,str);                        
                }
                else{
                    for (i = table->WubiDict->iHZLastInputCount-fwb->iTableNewPhraseHZCount; i >= 0&&i<table->WubiDict->iHZLastInputCount; i++){
                        strcat(strHZ, table->WubiDict->hzLastInput[i%PHRASE_MAX_LENGTH].strHZ);
                    }  
                }
                if(TableCalPhraseCode(table->WubiDict, strHZ,strCode)){
                    addUsrParse(fwb,1,strHZ,strCode);  
                }
                return IRV_CLEAN;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE)) {
                fwb->bIsTableAddPhrase = false;
                fwb->bIsTableAddPhraseByClip = false;
                FcitxInputStateSetIsDoInputOnly(input, false);   
                addUsrParse(fwb,2,"","");               
                return IRV_CLEAN;
            } else if (FcitxHotkeyIsHotKey(sym, state, FreewbCTRL_ENTER)) {
                fwb->bIsTableAddPhrase = false;
                fwb->bIsTableAddPhraseByClip = false;
                FcitxInputStateSetIsDoInputOnly(input, false);   
                int i;
                char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                char strCode[5];
                memset(strCode,0,5);
                if(fwb->bIsTableAddPhraseByClip){
                    char* str = getClipboard(fwb);
                    int strLen=fcitx_utf8_strlen(str);
                    for (i = fwb->iTableNewPhraseHZCount; i >= 0&&i<strLen; i++){
                        str = str + fcitx_utf8_char_len(str);
                    }  
                    strcpy(strHZ,str);                        
                }   
                else{
                    for (i = table->WubiDict->iHZLastInputCount-fwb->iTableNewPhraseHZCount; i >= 0&&i<table->WubiDict->iHZLastInputCount; i++){
                        strcat(strHZ, table->WubiDict->hzLastInput[i%PHRASE_MAX_LENGTH].strHZ);
                    }  
                }
                if(TableCalPhraseCode(table->WubiDict, strHZ,strCode))
                    addUsrParse(fwb,3,strHZ,strCode);               
                return IRV_CLEAN;
            } else {
                return IRV_DO_NOTHING;
            }
        }
        else if (fwb->bIsTableDelPhrase) {
            if (FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)) {
                fwb->bIsTableDelPhrase = false;
                FcitxInputStateSetIsDoInputOnly(input, false);   
                if(fwb->pLastCommitRecord)
                     deleteUsrParse(fwb,1,fwb->pLastCommitRecord->strHZ,fwb->pLastCommitRecord->strCode);            
                return IRV_CLEAN;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE)) {
                fwb->bIsTableDelPhrase = false;
                FcitxInputStateSetIsDoInputOnly(input, false);   
                deleteUsrParse(fwb,2,"","");               
                return IRV_CLEAN;
            } else {
                return IRV_DO_NOTHING;
            }
        }   
   
        if ((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkTableAddPhrase)&&!fwb->bIsTempEnglish)||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_ADD_PHRASE))) {
            fwb->bIsTempEnglish = false;
            if (!fwb->bIsTableAddPhrase&&table->tableType!=FREE_PINYIN) {
                if (table->WubiDict->iHZLastInputCount <= 1 || !table->WubiDict->bRule) //词组最少为两个汉字
                    return IRV_CLEAN;
                fwb->bIsTableAddPhrase = true;
                fwb->bIsTableAddPhraseByClip = false;
                fwb->iTableNewPhraseHZCount=2;
                
                FcitxInputStateSetIsDoInputOnly(input, true);
                FcitxInputStateSetShowCursor(input, false);

                FcitxInstanceCleanInputWindow(instance);
                int i;
                char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
                memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                char strCode[5];
                memset(strCode,0,5);
                for (i = table->WubiDict->iHZLastInputCount-fwb->iTableNewPhraseHZCount; i >= 0&&i<table->WubiDict->iHZLastInputCount; i++){
                    strcat(strHZ, table->WubiDict->hzLastInput[i%PHRASE_MAX_LENGTH].strHZ);
                }    
                if(TableCalPhraseCode(table->WubiDict, strHZ,strCode))
                    addUsrParse(fwb,0,strHZ,strCode);
                retVal = IRV_DO_NOTHING;
            } else
                retVal = IRV_TO_PROCESS;
            return retVal;
        } 
        
        if ((FcitxHotkeyIsHotKey(sym, state, fwb->hkTableAddPhraseByClip)&&!fwb->bIsTempEnglish)) {
            if (!fwb->bIsTableAddPhrase) {
                char* str = getClipboard(fwb);
                fwb->iTableNewPhraseHZCount=fcitx_utf8_strlen(str);
                if (fwb->iTableNewPhraseHZCount <= 1 || fwb->iTableNewPhraseHZCount >= PHRASE_MAX_LENGTH ||!table->WubiDict->bRule) //词组最少为两个汉字
                    return IRV_CLEAN; 
                fwb->bIsTableAddPhrase = true;
                fwb->bIsTableAddPhraseByClip = true;
                FcitxInputStateSetIsDoInputOnly(input, true);
                FcitxInputStateSetShowCursor(input, false);

                FcitxInstanceCleanInputWindow(instance);
//                 int i;
//                 char strHZ[PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1];
//                 memset(strHZ,0,PHRASE_MAX_LENGTH*UTF8_MAX_LENGTH+1);
                char strCode[5];
                memset(strCode,0,5);
                
                if(TableCalPhraseCode(table->WubiDict, str,strCode))
                    addUsrParse(fwb,0,str,strCode);
                retVal = IRV_DO_NOTHING;
            } else
                retVal = IRV_TO_PROCESS;
            return retVal;
        }        
        else if ((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkTableDelPhrase)&&!fwb->bIsTempEnglish)||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_DELETE_PHRASE))) {
            fwb->bIsTempEnglish = false;
            if (!fwb->bIsTableDelPhrase&&table->tableType!=FREE_PINYIN) {
                if (table->WubiDict->iHZLastInputCount < 1) //词组最少为一个汉字
                    return IRV_CLEAN;
                fwb->bIsTableDelPhrase = true;
                
                FcitxInputStateSetIsDoInputOnly(input, true);
                FcitxInputStateSetShowCursor(input, false);

                FcitxInstanceCleanInputWindow(instance);
                if(fwb->pLastCommitRecord)
                     deleteUsrParse(fwb,0,fwb->pLastCommitRecord->strHZ,fwb->pLastCommitRecord->strCode);
                retVal = IRV_DO_NOTHING;
            } else
                retVal = IRV_TO_PROCESS;

            return retVal;
        }
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkReverseCheck)&&!fwb->bIsTempEnglish)
            ||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_REVERSE_CHECK))){
            fwb->bIsTempEnglish = false;
            if(fwb->pLastCommitRecord){
                dictQuery(fwb,fwb->pLastCommitRecord->strHZ);
            }
            return IRV_CLEAN;
        }
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->hkReverseCheckByClip)&&!fwb->bIsTempEnglish)){
            char* str = getClipboard(fwb);
            dictQuery(fwb,str);
            return IRV_CLEAN;
        }
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSwitchChttrans)&&!fwb->bIsTempEnglish)){
            fwb->config.bIsTraditional = !fwb->config.bIsTraditional;
            switchChttrans(fwb,fwb->config.bIsTraditional);
            return IRV_CLEAN;
        }        
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkShowHideCandiWin)&&!fwb->bIsTempEnglish)
            ||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_HIDE_CANDWIN))){
            switchCandiwinState(fwb);
            fwb->bIsTempEnglish = false;
            return IRV_CLEAN;
        }    
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkShowHideToolbar)&&!fwb->bIsTempEnglish)
            ||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_HIDE_TOOLBAR))){
            switchToolbarState(fwb);
            fwb->bIsTempEnglish = false;
            return IRV_CLEAN;
        }  
        else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSwitchSkin)){
            switchSkin(fwb);
            fwb->bIsTempEnglish = false;
            return IRV_CLEAN;
        }  
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSwitchVKb)&&!fwb->bIsTempEnglish)
            ||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_SWITCH_KEYBORD))){
            switchVk(fwb,0);
            fwb->bIsTempEnglish = false;
            return IRV_CLEAN;
        }  
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSwitchCharSet)&&!fwb->bIsTempEnglish)
            ||(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_SWITCH_CHAR_SET))){
            switchCharSet(fwb);
            fwb->bIsTempEnglish = false;
            fwb->config.bIsGBK = !fwb->config.bIsGBK;
            return IRV_CLEAN;
        } 
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSmartPunc)&&!fwb->bIsTempEnglish)){
            fwb->config.bUseSmartPunc = !fwb->config.bUseSmartPunc;
            switchSmartPunc(fwb,fwb->config.bUseSmartPunc);
            return IRV_CLEAN;
        }
        else if(FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE))
        {
            if (!fwb->bIsTableAddPhrase && !fwb->bIsTableDelPhrase &&
            !fwb->bIsTableAdjustOrder ){
                if(!FcitxInputStateGetRawInputBufferSize(input)){
                    if(table->tableType!=FREE_PINYIN&&table->WubiDict->iHZLastInputCount>0)
                        table->WubiDict->iHZLastInputCount--;
                    fwb->bHasQuickDelete = true;
                }
                retVal = IRV_TO_PROCESS;
            }
            if(fwb->config.bInputVoice)
                playSound(SOUND_BACK);
        }
        else if((FcitxHotkeyIsHotKey(sym, state, fwb->config.hkQuickDelete)&&!FcitxInputStateGetRawInputBufferSize(input))){
            if(fwb->bHasQuickDelete)
                return IRV_DO_NOTHING;
            const char * strlast = FcitxInputStateGetLastCommitString(input);
            int a=fcitx_utf8_strlen(strlast);
            while(a--){
                FcitxInstanceForwardKey(instance, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, FcitxKey_BackSpace, FcitxKeyState_None);
                if(table->tableType!=FREE_PINYIN)
                    table->WubiDict->iHZLastInputCount--;
            }
            fwb->bHasQuickDelete = true;
            fwb->bIsTempEnglish = false;
            return IRV_DO_NOTHING;
            
        }
        else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSwitchTable) && !fwb->bIsTempEnglish){
            switchTable(fwb);
            return IRV_CLEAN;
        }
        else if(FcitxHotkeyIsHotKey(sym, state, FreewbCAPS_LOCK) && !fwb->bIsTempEnglish){
            FcitxInstanceResetInput(instance);
            return IRV_CLEAN;
        }        
        else if(state==FcitxKeyState_Ctrl&&sym>='0'&&sym<='9'){
            int index = sym - '1';
            if(sym == '0'){
                index = 9;
            }
            if(index<0||index>FcitxCandidateWordGetCurrentWindowSize(candList)-1)
                return IRV_DO_NOTHING;
            else{
                TABLECANDWORD* tableCandWord = FcitxCandidateWordGetByIndex(candList,index)->priv;
                if(tableCandWord->flag == CT_NORMAL){
                    RECORD* recTemp =tableCandWord->candWord.record;
                    if(fwb->table->tableType==FREE_PINYIN)
                        adjustOrder(table,table->PinyinDict,recTemp->strHZ,recTemp->strCode);
                    else
                        adjustOrder(table,table->WubiDict,recTemp->strHZ,strCodeInput);
                }
                else if(tableCandWord->flag == CT_AUTOPHRASE){
                    adjustOrder(table,table->WubiDict,tableCandWord->candWord.autoPhrase->strHZ,strCodeInput);
                }
                
                return FreeWubiGetCandWords(fwb);
            }
                
        }
        else if(state==FcitxKeyState_Ctrl&&digitalNumberTrans(sym)<=10&&!fwb->bIsTempEnglish){
            int index = digitalNumberTrans(sym) - 1;
            if(index<0||index>FcitxCandidateWordGetCurrentWindowSize(candList)-1)
                return IRV_DO_NOTHING;
            else{
                TABLECANDWORD* tableCandWord = FcitxCandidateWordGetByIndex(candList,index)->priv;
                if(tableCandWord->flag == CT_NORMAL){
                    RECORD* recTemp =tableCandWord->candWord.record;
                    if(recTemp->type == RECORDTYPE_NORMAL)
                        recTemp->type = RECORDTYPE_UNCOMMON;
                    else if(recTemp->type == RECORDTYPE_UNCOMMON)
                        recTemp->type = RECORDTYPE_NORMAL;
                    recTemp->owner->iTableChanged ++;
                    SaveTableDict(table);
                }               
                return FreeWubiGetCandWords(fwb);
            }
        }
        else if(state==FcitxKeyState_None&&sym== FcitxKey_Delete&&!fwb->bIsTempEnglish&&FcitxCandidateWordPageCount(candList)){
            fwb->bisDelNumber = true;
            return IRV_DO_NOTHING;
        }               
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_SWITCH_UNCOMMON)){
            fwb->bIsTempEnglish = false;
            if(fwb->pLastCommitRecord ){
                RECORD * recTemp = TableFindPhraseByCode(fwb->pLastCommitRecord->owner,fwb->pLastCommitRecord->strCode,fwb->pLastCommitRecord->strHZ);
                if(recTemp){
                    if(recTemp->type == RECORDTYPE_NORMAL){
                        recTemp->type = RECORDTYPE_UNCOMMON;
                        switchUncommon(fwb,recTemp->strHZ,1);
                    }
                    else if(recTemp->type == RECORDTYPE_UNCOMMON){
                        recTemp->type = RECORDTYPE_NORMAL;
                        switchUncommon(fwb,recTemp->strHZ,0);
                    }
                    recTemp->owner->iTableChanged ++;
                    SaveTableDict(table);
                }               
            }
            return  IRV_CLEAN;
        }  
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_RECODE_PROOF)){
            fwb->bIsTempEnglish = false;
            fwb->config.bRecodeProof = !fwb->config.bRecodeProof;
            switchRecodeProof(fwb,fwb->config.bRecodeProof);
            return IRV_CLEAN;
        } 
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_CHTTRANS)){
            fwb->bIsTempEnglish = false;
            fwb->config.bIsTraditional = !fwb->config.bIsTraditional;
            switchChttrans(fwb,fwb->config.bIsTraditional);
            return IRV_CLEAN;
        }    
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_OPEN_CONFIG)){
            fwb->bIsTempEnglish = false;
            openSysConf(fwb);
            return IRV_CLEAN;
        }
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_VERSION)){
            fwb->bIsTempEnglish = false;
            showVersion(fwb);
            return IRV_CLEAN;
        }   
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_PROFEESINAL)){
            fwb->bIsTempEnglish = false;
            openProfessionalConf(fwb);
            return IRV_CLEAN;
        } 
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_QUICK_TABLE)){
            fwb->bIsTempEnglish = false;
            modQuickTable(fwb);
            return IRV_CLEAN;
        }
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_USER_TABLE)){
            fwb->bIsTempEnglish = false;
            modUserTable(fwb);
            return IRV_CLEAN;
        }
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_WUBI_TABLE)){
            fwb->bIsTempEnglish = false;
            modWubiTable(fwb);
            return IRV_CLEAN;
        }
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_PINYIN_TABLE)){
            fwb->bIsTempEnglish = false;
            modPinyinTable(fwb);
            return IRV_CLEAN;
        }
        else if(fwb->bIsTempEnglish && !strcmp(strCodeInput+1,STR_CONF_DIR)){
            fwb->bIsTempEnglish = false;
            openConfDir(fwb);
            return IRV_CLEAN;
        } 
        if (!fwb->bIsTableDelPhrase && !fwb->bIsTableAdjustOrder && !fwb->bIsTempEnglish) {
            if (FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)) {
                if(fwb->config.bInputVoice)
                    playSound(SOUND_BACK);
                if (!FcitxInputStateGetRawInputBufferSize(input)) {
                    FcitxInputStateSetIsInRemind(input, false);
                    return IRV_DONOT_PROCESS_CLEAN;
                }
                FcitxInputStateSetRawInputBufferSize(input, FcitxInputStateGetRawInputBufferSize(input) - 1);
                strCodeInput[FcitxInputStateGetRawInputBufferSize(input)] = '\0';
                if (FcitxInputStateGetRawInputBufferSize(input))
                    retVal = IRV_DISPLAY_CANDWORDS;
                else
                    return IRV_CLEAN;
            } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)&&(
                FcitxInputStateGetRawInputBufferSize(input)||FcitxCandidateWordPageCount(candList) != 0) ) {
                if(fwb->config.bInputVoice)
                    playSound(SOUND_SAPCE);
                if (FcitxCandidateWordPageCount(candList) == 0 ) {
                    FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), FcitxInputStateGetRawInputBuffer(input));
                    FcitxInputStateSetRawInputBufferSize(input, 0);
                    FcitxInputStateGetRawInputBuffer(input)[0] = '\0';
                    FcitxInputStateSetIsInRemind(input, false);
                    FcitxInstanceCleanInputWindow(instance);
                    FcitxUIUpdateInputWindow(instance);
                    return IRV_DO_NOTHING;
                }
                else {
                    return FcitxCandidateWordChooseByIndex(candList, 0);
                }
            }
            else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkSecondRecode)){
                if(FcitxCandidateWordGetByIndex(candList,1)){
                    return FcitxCandidateWordChooseByIndex(candList, 1);                   
                }
                else
                    retVal = IRV_TO_PROCESS;
            }else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkThirdRecode)){
                if(FcitxCandidateWordGetByIndex(candList,2)){
                    return FcitxCandidateWordChooseByIndex(candList, 2);       
                }
                else
                    retVal = IRV_TO_PROCESS;
            }else if(FcitxHotkeyIsHotKey(sym, state, fwb->config.hkAlternativePrevPage) || FcitxHotkeyIsHotKey(sym, state, fwb->config.hkAlternativeNextPage)){
                    return IRV_TO_PROCESS;
            }
            else if(FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER) && FcitxInputStateGetRawInputBufferSize(input)){
                if(!fwb->config.bEnterClear)
                    FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), strCodeInput);
                fwb->bIsTempEnglish = false;
                return IRV_CLEAN;
            }  
            else {
                 retVal = IRV_TO_PROCESS;
            }             
            char *matchStr = NULL;
            if(profile->bUseWidePunc && FcitxHotkeyIsHotKeySimple(sym,state))
                matchStr = matchVkBoard(sym,VKM_INPUT_USER_MARK);
            if(matchStr && *matchStr && (!fwb->config.bAutoHalf || (strcmp(matchStr,"，")&& strcmp(matchStr,"。")))){
                if (FcitxCandidateWordPageCount(candList)) {
                    FcitxCandidateWord* candWord = FcitxCandidateWordGetCurrentWindow(candList);
                    if (candWord->owner == fwb) {
                        INPUT_RETURN_VALUE ret = FreeWubiGetCandWord(fwb, candWord);
                        if (ret & IRV_FLAG_PENDING_COMMIT_STRING) {
                            strcat(output_str,matchStr);
                            FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), output_str);
                            strCodeInput[0] = sym;
                            strCodeInput[1] = '\0';
                            FcitxInputStateSetRawInputBufferSize(input, 1);
                            FcitxInstanceResetInput(instance);
                            return IRV_CLEAN;                            
                        }
                    }
                }
                FcitxInstanceCommitString(instance,FcitxInstanceGetCurrentIC(instance),matchStr);
                FcitxInstanceResetInput(instance);
                return IRV_CLEAN;
            }
        }
    }  
    if (!FcitxInputStateGetRawInputBufferSize(input) && !FcitxInputStateGetIsInRemind(input) && !fwb->bIsTempEnglish){
        if(FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)&&fwb->config.bFullSpace){
            FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), "　");
            return IRV_DO_NOTHING;
        }
        return IRV_TO_PROCESS;
    } 
    if (!FcitxInputStateGetIsInRemind(input)) {
        if (fwb->bIsTableDelPhrase || fwb->bIsTableAdjustOrder )
            FcitxInputStateSetIsDoInputOnly(input, true);
    }

    if (fwb->bIsTableDelPhrase || fwb->bIsTableAdjustOrder )
        FcitxInputStateSetShowCursor(input, false);
     else if(!FcitxInputStateGetIsInRemind(input)){
            FcitxInputStateSetShowCursor(input, true);
            FcitxInputStateSetCursorPos(input, strlen(FcitxInputStateGetRawInputBuffer(input)));
            FcitxInputStateSetClientCursorPos(input, strlen(FcitxInputStateGetRawInputBuffer(input)));
     }
    return retVal;
}
void UpdateHZLastInput(TableMetaData* table, const char *str)
{
    unsigned int i;
    unsigned int str_len = fcitx_utf8_strlen(str);
    TableDict *const tableDict = table->WubiDict;
    if(!tableDict)
        return;
    SINGLE_HZ *const hzLastInput = tableDict->hzLastInput;  

    for (i = 0;i < str_len;i++) {
        unsigned int char_len = fcitx_utf8_char_len(str);
        strncpy(hzLastInput[tableDict->iHZLastInputCount%PHRASE_MAX_LENGTH].strHZ,
                str, char_len);
        hzLastInput[tableDict->iHZLastInputCount%PHRASE_MAX_LENGTH].strHZ[char_len] = '\0';
        str += char_len;
        tableDict->iHZLastInputCount++;
    }
}
static INPUT_RETURN_VALUE FreeWubiGetCandWord(void* arg, FcitxCandidateWord* candWord){
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    FcitxInstance *instance = fwb->owner;
    TableMetaData* table = fwb->table;
    FcitxInputState* input = FcitxInstanceGetInputState(instance);
    TABLECANDWORD* tableCandWord = candWord->priv;
    INPUT_RETURN_VALUE retVal = _TableGetCandWord(table, tableCandWord, true);  
    if (retVal & IRV_FLAG_PENDING_COMMIT_STRING) {
        fwb->bHasQuickDelete = false; 
        if ( fcitx_utf8_strlen(FcitxInputStateGetOutputString(input)) >= 1 )
            UpdateHZLastInput(table, FcitxInputStateGetOutputString(input));       
        if (fcitx_utf8_strlen(FcitxInputStateGetOutputString(input)) == 1&&fwb->config.iAutoPhraseOpt){
            strcpy(table->autoRecord->recordHZ[table->autoRecord->recordIndex%4].strHZ,FcitxInputStateGetOutputString(input));
            if(TableCreateAutoPhrase(table,table->autoRecord->recordIndex)){
                FcitxInputStateGetRawInputBuffer(input)[0] = '\0';
                FcitxInputStateSetRawInputBufferSize(input, 0);
                FcitxInputStateSetIsInRemind(input,1);
                //FcitxCandidateWordReset(cand_list);  
                retVal = IRV_COMMIT_STRING_REMIND;}
            table->autoRecord->recordIndex++;
        }
        else{
            table->autoRecord->recordIndex = 0;
        }
        if(fwb->pLastCommitRecord&&fwb->config.bAutoAdjustOrder)
            adjustOrder(fwb->table,fwb->pLastCommitRecord->owner,fwb->pLastCommitRecord->strHZ,fwb->pLastCommitRecord->strCode); 
    }
    return retVal;
}
static INPUT_RETURN_VALUE FreeWubiGetNoneCandWord(void* arg, FcitxCandidateWord* candWord){
    return IRV_CLEAN;
}
INPUT_RETURN_VALUE TableGetRepeateCandWords(TableMetaData* table)
{
    Fcitxfreewubi* fwb = table->owner;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);

    FcitxInstanceCleanInputWindowUp(instance);
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, FcitxInputStateGetRawInputBuffer(input));
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT | MSG_DONOT_COMMIT_WHEN_UNFOCUS, FcitxInputStateGetRawInputBuffer(input));
    FcitxInputStateSetCursorPos(input, FcitxInputStateGetRawInputBufferSize(input));
    FcitxInputStateSetClientCursorPos(input, 0);
    
    TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
    tableCandWord->flag = CT_REPEATE;
    tableCandWord->candWord.record = fwb->pLastCommitRecord;
    FcitxCandidateWord candWord;
    candWord.callback = FreeWubiGetCandWord;
    candWord.owner = fwb;
    candWord.priv = tableCandWord;
    candWord.strExtra = NULL;
    char * speStrHZ =tableCandWord->candWord.record->strHZ;
    if(tableCandWord->candWord.record->type == RECORDTYPE_CONSTRUCT){
        candWord.strWord  = matchTime(speStrHZ);
    }
    else
        candWord.strWord = strdup(tableCandWord->candWord.record->strHZ);    
    candWord.wordType = MSG_OTHER;
    FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);

    return IRV_DISPLAY_CANDWORDS;
}
INPUT_RETURN_VALUE TableGetQuickCandWords(TableMetaData* table)
{
    Fcitxfreewubi* fwb = table->owner;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
    int retVal = IRV_DISPLAY_CANDWORDS;
    char output_str[10];
    int puncNumber = -1;
    FcitxInstanceCleanInputWindowUp(instance);
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, FcitxInputStateGetRawInputBuffer(input));
    FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT | MSG_DONOT_COMMIT_WHEN_UNFOCUS, FcitxInputStateGetRawInputBuffer(input));
    FcitxInputStateSetCursorPos(input, FcitxInputStateGetRawInputBufferSize(input));
    FcitxInputStateSetClientCursorPos(input, 0);
    FcitxInputStateSetShowCursor(input, true);
    QUCIK_TABLE* quickTable[3] = {NULL,NULL,NULL}; 
    if(FcitxInputStateGetRawInputBufferSize(input)==1){
        puncNumber = isPuncKey(FcitxInputStateGetRawInputBuffer(input)[0]);
        FcitxProfile* profile = FcitxInstanceGetProfile(instance);
        if(-1!=puncNumber&&fwb->config.bUseSmartPunc){
            matchPunc(output_str,puncNumber,profile->bUseWidePunc);
        }
        else
            strcpy(output_str,FcitxInputStateGetRawInputBuffer(input));
            switchTempKey(output_str,profile->bUseWidePunc);
            quickTable[0] = fcitx_utils_new(QUCIK_TABLE);
            if(-1!=puncNumber)
                quickTable[0]->key = 0;
            else
                quickTable[0]->key = FcitxInputStateGetRawInputBuffer(input)[0];
            strcpy(quickTable[0]->value,output_str);
            quickTable[0]->next = NULL;
    }
    else if(FcitxInputStateGetRawInputBufferSize(input)>1){
        if(!fwb->bIsTempEnglish)
            quickTable[0] = findQuickPharse(table,FcitxInputStateGetRawInputBuffer(input)[1]);
        else{
            char* strOut1 = matchMoney(FcitxInputStateGetRawInputBuffer(input)+1);
            if(!strOut1)
                strOut1 = matchtimeManul(FcitxInputStateGetRawInputBuffer(input)+1,0);
            if(strOut1){
                quickTable[0] = fcitx_utils_new(QUCIK_TABLE);
                quickTable[0]->key = FcitxInputStateGetRawInputBuffer(input)[0];
                strcpy(quickTable[0]->value,strOut1);
                quickTable[0]->next = NULL;     
                free(strOut1);
            }
            char* strOut2 = matchNumber(FcitxInputStateGetRawInputBuffer(input)+1);
            if(!strOut2)
                strOut2 = matchtimeManul(FcitxInputStateGetRawInputBuffer(input)+1,1);
            if(strOut2){
                quickTable[1] = fcitx_utils_new(QUCIK_TABLE);
                quickTable[1]->key = FcitxInputStateGetRawInputBuffer(input)[0];
                strcpy(quickTable[1]->value,strOut2);
                quickTable[1]->next = NULL;     
                free(strOut2);
            }
            char* strOut3 = matchNumberSim(FcitxInputStateGetRawInputBuffer(input)+1);
            if(!strOut3)
                strOut3 = matchtimeManul(FcitxInputStateGetRawInputBuffer(input)+1,2);
            if(strOut3){
                quickTable[2] = fcitx_utils_new(QUCIK_TABLE);
                quickTable[2]->key = FcitxInputStateGetRawInputBuffer(input)[0];
                strcpy(quickTable[2]->value,strOut3);
                quickTable[2]->next = NULL;     
                free(strOut3);
            }            
        }
    }
    int i=0;
    for(;i<3;i++){
        if(quickTable[i]){
            TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
            tableCandWord->flag = CT_QUICK;        
            tableCandWord->candWord.qucikPhrase = quickTable[i];
            FcitxCandidateWord candWord;
            candWord.callback = FreeWubiGetCandWord;
            candWord.owner = fwb;
            candWord.priv = tableCandWord;
            candWord.strExtra = NULL;
            candWord.strWord = strdup(tableCandWord->candWord.qucikPhrase->value);
            candWord.wordType = MSG_OTHER;
            FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
        }        
    }

    if(FcitxInputStateGetRawInputBufferSize(input)!=1&&!fwb->bIsTempEnglish){
        retVal = FcitxCandidateWordChooseByIndex(candList, 0);
        if(retVal != IRV_COMMIT_STRING)
            retVal = IRV_CLEAN;
    }    
    return retVal;
}
INPUT_RETURN_VALUE FreeWubiGetCandWords (void *arg){
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    TableMetaData* table = fwb->table;
    RECORD         *recTemp;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);     
    if (FcitxInputStateGetRawInputBuffer(input)[0] == '\0')
        return IRV_TO_PROCESS;

    if (FcitxInputStateGetIsInRemind(input))
        return TableGetRemindCandWords(table);
        
    if(FcitxInputStateGetRawInputBuffer(input)[0]=='z'&&FcitxInputStateGetRawInputBufferSize(input)==1&&fwb->pLastCommitRecord){
        return TableGetRepeateCandWords(table);
    } 
    if(FcitxInputStateGetRawInputBuffer(input)[0]==fwb->config.QuickInputKey || fwb->bIsTempEnglish 
        || (FcitxInputStateGetRawInputBuffer(input)[0]==fwb->config.unCommonKey && FcitxInputStateGetRawInputBufferSize(input)==1))
        return TableGetQuickCandWords(table);
    if (TableFindFirstMatchCode(table, FcitxInputStateGetRawInputBuffer(input), !fwb->config.bCodeRemind, true) == -1 ){
        if (FcitxInputStateGetRawInputBufferSize(input)) {
            FcitxMessagesSetMessageCount(FcitxInputStateGetPreedit(input), 0);
            FcitxMessagesSetMessageCount(FcitxInputStateGetClientPreedit(input), 0);
            FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, FcitxInputStateGetRawInputBuffer(input));
            FcitxMessageType type = MSG_INPUT;
            FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetClientPreedit(input), type, FcitxInputStateGetRawInputBuffer(input));
            FcitxInputStateSetCursorPos(input, strlen(FcitxInputStateGetRawInputBuffer(input)));
            FcitxInputStateSetClientCursorPos(input, 0);
        }
        return IRV_DISPLAY_CANDWORDS;
    }
    UT_array candTemp,candWubi,candPinyin;
    utarray_init(&candTemp, fcitx_ptr_icd);
    utarray_init(&candWubi, fcitx_ptr_icd);
    utarray_init(&candPinyin, fcitx_ptr_icd);
    if(table->tableType!=FREE_PINYIN){
        while (table->WubiDict->currentRecord && table->WubiDict->currentRecord != table->WubiDict->recordHead) {
            if(FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey){
                char * strInput = FcitxInputStateGetRawInputBuffer(input);
                strInput++;
                if (table->WubiDict->currentRecord->type == RECORDTYPE_UNCOMMON&&
                    !TableCompareCode(strInput, table->WubiDict->currentRecord->strCode, !fwb->config.bCodeRemind)) {
                    if(fwb->config.bIsTraditional){
                        char strSignelHZ[10] = {0};
                        int len =fcitx_utf8_strlen(table->WubiDict->currentRecord->strHZ);
                        if(len == 1)
                            strcpy(strSignelHZ,table->WubiDict->currentRecord->strHZ);
                        else
                            strncpy(strSignelHZ,table->WubiDict->currentRecord->strHZ,fcitx_utf8_char_len(table->WubiDict->currentRecord->strHZ));
                        recTemp = table->WubiDict->s2tSignleHZ[CalHZIndex(strSignelHZ)];
                        if(!recTemp){
                            TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                            TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                            utarray_push_back(&candWubi, &tableCandWord);                                
                        }
                        else{
                            while(recTemp!=table->WubiDict->s2tRecordHead && !strncmp(recTemp->strCode,strSignelHZ,strlen(strSignelHZ)) && strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ) ){
                                recTemp = recTemp->next;
                            }
                            if(recTemp==table->WubiDict->s2tRecordHead || strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ)){
                                TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                                utarray_push_back(&candWubi, &tableCandWord);                                 
                            }
                            else{
                                while(recTemp!=table->WubiDict->s2tRecordHead && !strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ) ){
                                    TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                    TableAddCandWord(recTemp, tableCandWord);
                                    tableCandWord->candWord.simpelRecord = table->WubiDict->currentRecord;
                                    utarray_push_back(&candWubi, &tableCandWord);  
                                    recTemp = recTemp->next;
                                }                                
                            }

                        }
                    }
                    else{
                        TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                        TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                        utarray_push_back(&candWubi, &tableCandWord);
                    }
                }            
            }
            else if ((fwb->config.bIsGBK||table->WubiDict->currentRecord->type != RECORDTYPE_UNCOMMON)&&
                !TableCompareCode(FcitxInputStateGetRawInputBuffer(input), table->WubiDict->currentRecord->strCode, !fwb->config.bCodeRemind)) {
                    if(fwb->config.bIsTraditional){
                        
                        char strSignelHZ[10] = {0};
                        int len =fcitx_utf8_strlen(table->WubiDict->currentRecord->strHZ);
                        if(len == 1)
                            strcpy(strSignelHZ,table->WubiDict->currentRecord->strHZ);
                        else
                            strncpy(strSignelHZ,table->WubiDict->currentRecord->strHZ,fcitx_utf8_char_len(table->WubiDict->currentRecord->strHZ));
                        recTemp = table->WubiDict->s2tSignleHZ[CalHZIndex(strSignelHZ)];
                        if(!recTemp){
                            TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                            TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                            utarray_push_back(&candWubi, &tableCandWord);                                
                        }
                        else{
                            while(recTemp!=table->WubiDict->s2tRecordHead && !strncmp(recTemp->strCode,strSignelHZ,strlen(strSignelHZ)) && strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ)){
                                recTemp = recTemp->next;
                            }
                            if(recTemp==table->WubiDict->s2tRecordHead || strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ)){
//                                 printf("111%s%s\n",recTemp->strCode,recTemp->strHZ);
                                TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                                utarray_push_back(&candWubi, &tableCandWord);                                 
                            }
                            else{
//                                 printf("222%s%s\n",recTemp->strCode,recTemp->strHZ);
                                while(recTemp!=table->WubiDict->s2tRecordHead && !strcmp(recTemp->strCode,table->WubiDict->currentRecord->strHZ)){
                                    TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                    TableAddCandWord(recTemp, tableCandWord);    
                                    tableCandWord->candWord.simpelRecord = table->WubiDict->currentRecord;
                                    utarray_push_back(&candWubi, &tableCandWord);          
                                    recTemp = recTemp->next;
                                }                                
                            }
//                             printf("%s%s\n",recTemp->strCode,recTemp->strHZ);
                        }
                    }                
                    else{
                        TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                        TableAddCandWord(table->WubiDict->currentRecord, tableCandWord);
                        utarray_push_back(&candWubi, &tableCandWord);
                    }
                    
            }
            table->WubiDict->currentRecord = table->WubiDict->currentRecord->next;
        }      
    }
/*        TABLECANDWORD** pcand = NULL;
    for (pcand = (TABLECANDWORD**) utarray_front(&candWubi);
            pcand != NULL;
            pcand = (TABLECANDWORD**) utarray_next(&candWubi, pcand)) {
                TABLECANDWORD* tableCandWord = *pcand;
                if(tableCandWord->candWord.record->type == RECORDTYPE_S2T)
                    printf("cccccc:%s,%s,%d\n",tableCandWord->candWord.simpelRecord->strCode,tableCandWord->candWord.simpelRecord->strHZ,FcitxInputStateGetRawInputBufferSize(input));
            }  */  
    if(table->tableType!=FREE_WUBI||FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey){
        while (table->PinyinDict->currentRecord && table->PinyinDict->currentRecord != table->PinyinDict->recordHead) {
            char * strInput = FcitxInputStateGetRawInputBuffer(input);
            if(FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey&&table->tableType==FREE_WUBI)
                strInput++;
            if (table->PinyinDict->currentRecord->type != RECORDTYPE_CONSTRUCT &&
                !TableCompareCode(strInput, table->PinyinDict->currentRecord->strCode, !fwb->config.bCodeRemind)) {
                    if(fwb->config.bIsTraditional){
                        char strSignelHZ[10] = {0};
                        int len =fcitx_utf8_strlen(table->PinyinDict->currentRecord->strHZ);
                        if(len == 1)
                            strcpy(strSignelHZ,table->PinyinDict->currentRecord->strHZ);
                        else
                            strncpy(strSignelHZ,table->PinyinDict->currentRecord->strHZ,fcitx_utf8_char_len(table->PinyinDict->currentRecord->strHZ));
                        recTemp = table->WubiDict->s2tSignleHZ[CalHZIndex(strSignelHZ)];
                        if(!recTemp){
                            TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                            TableAddCandWord(table->PinyinDict->currentRecord, tableCandWord);
                            utarray_push_back(&candPinyin, &tableCandWord);                                
                        }
                        else{
                            while(recTemp!=table->WubiDict->s2tRecordHead && !strncmp(recTemp->strCode,strSignelHZ,strlen(strSignelHZ)) && strcmp(recTemp->strCode,table->PinyinDict->currentRecord->strHZ)){
                                recTemp = recTemp->next;
                            }
                            if(recTemp==table->WubiDict->s2tRecordHead || strcmp(recTemp->strCode,table->PinyinDict->currentRecord->strHZ)){
                                TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                TableAddCandWord(table->PinyinDict->currentRecord, tableCandWord);
                                utarray_push_back(&candPinyin, &tableCandWord);                                 
                            }
                            else{
                                while(recTemp!=table->WubiDict->s2tRecordHead && !strcmp(recTemp->strCode,table->PinyinDict->currentRecord->strHZ) ){
                                    TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                                    TableAddCandWord(recTemp, tableCandWord);
                                    tableCandWord->candWord.simpelRecord = table->PinyinDict->currentRecord;
                                    utarray_push_back(&candPinyin, &tableCandWord);  
                                    recTemp = recTemp->next;
                                }                                
                            }

                        }
                    }
                    else{
                        TABLECANDWORD* tableCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
                        TableAddCandWord(table->PinyinDict->currentRecord, tableCandWord);
                        utarray_push_back(&candPinyin, &tableCandWord);
                    }                
            }
            table->PinyinDict->currentRecord = table->PinyinDict->currentRecord->next;
        }
    }
   
    TABLECANDWORD* autoCandWord = NULL;
    if(fwb->config.iAutoPhraseOpt&&table->currentPhrase){
        if(!TableCompareCode(FcitxInputStateGetRawInputBuffer(input), table->currentPhrase->strCode, 1)){
            autoCandWord = fcitx_utils_malloc0(sizeof(TABLECANDWORD));
            TableAddAutoCandWord(table->currentPhrase, autoCandWord);
            utarray_push_back(&candWubi, &autoCandWord);
        }
    }  
    
    sortCandwords(&candWubi,&candPinyin,&candTemp);
    boolean isRepeat = false;
    TABLECANDWORD** pcand = NULL;
    for (pcand = (TABLECANDWORD**) utarray_front(&candTemp);
            pcand != NULL;
            pcand = (TABLECANDWORD**) utarray_next(&candTemp, pcand)) {
        TABLECANDWORD* tableCandWord = *pcand;
        FcitxCandidateWord candWord;
        candWord.callback = FreeWubiGetCandWord;
        candWord.owner = fwb;
        candWord.priv = tableCandWord;
        if(tableCandWord->flag == CT_AUTOPHRASE){
            if(isRepeat)
                continue;
            candWord.strWord = strdup(tableCandWord->candWord.autoPhrase->strHZ);
        }
        else if(tableCandWord->flag == CT_NORMAL){
            char * speStrHZ =tableCandWord->candWord.record->strHZ;
            if(tableCandWord->candWord.record->type == RECORDTYPE_CONSTRUCT){
                if(autoCandWord && strcmp(tableCandWord->candWord.record->strCode,autoCandWord->candWord.autoPhrase->strCode)==0 &&
                    strcmp(tableCandWord->candWord.record->strHZ,autoCandWord->candWord.autoPhrase->strHZ)==0)
                    isRepeat = true;       //如果与自动造词的词组重复，则不显示自动造词的词组
                candWord.strWord  = matchTime(speStrHZ);
            }
            else{
                candWord.strWord = strdup(tableCandWord->candWord.record->strHZ);
            }
        }
        if(fwb->config.bIsTraditional && tableCandWord->candWord.record->type!=RECORDTYPE_S2T){
            //free(candWord.strWord);
            char *strTemp = s2tConvers(table,candWord.strWord);
            free(candWord.strWord);
            candWord.strWord = strTemp;
        }
            
        candWord.strExtra = NULL;
        candWord.wordType = MSG_OTHER;
        const char* pstr = NULL;
        const char* pstrS2t = NULL;
        boolean isSinglePinyin = false;
        boolean isSingleS2t = false;
        if (tableCandWord->flag == CT_NORMAL){      
            if(tableCandWord->candWord.record->type == RECORDTYPE_S2T && fcitx_utf8_strlen(tableCandWord->candWord.record->strHZ) == 1){
                pstrS2t = tableCandWord->candWord.record->strCode;
                isSingleS2t = true;
            }   
            if((tableCandWord->candWord.record->owner->tableType == FREE_PINYIN ) || (tableCandWord->candWord.record->type == RECORDTYPE_S2T &&tableCandWord->candWord.simpelRecord->owner->tableType == FREE_PINYIN )){
                if(fcitx_utf8_strlen(tableCandWord->candWord.record->strHZ) == 1){
                        if(!strcmp(FcitxInputStateGetRawInputBuffer(input),tableCandWord->candWord.record->strCode)
                        || (tableCandWord->candWord.record->type == RECORDTYPE_S2T && !strcmp(FcitxInputStateGetRawInputBuffer(input),tableCandWord->candWord.simpelRecord->strCode))) {
                        recTemp = table->WubiDict->tableSingleHZ[CalHZIndex(tableCandWord->candWord.record->strHZ)];
                        if (!recTemp)
                            pstr = (char *) NULL;
                        else{
                            pstr = recTemp->strCode;
                            isSinglePinyin = true;
                        }
                    }
                    else if((!strcmp(FcitxInputStateGetRawInputBuffer(input)+1,tableCandWord->candWord.record->strCode) && FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey)
                        || (tableCandWord->candWord.record->type == RECORDTYPE_S2T && !strcmp(FcitxInputStateGetRawInputBuffer(input)+1,tableCandWord->candWord.simpelRecord->strCode) && FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey)) {
                        recTemp = table->WubiDict->tableSingleHZ[CalHZIndex(tableCandWord->candWord.record->strHZ)];
                        if (!recTemp)
                            pstr = (char *) NULL;
                        else{
                            pstr = recTemp->strCode;
                            isSinglePinyin = true;
                        }
                    }
                }
                else if(table->tableType == FREE_WUBI){
                    if(tableCandWord->candWord.record->type == RECORDTYPE_S2T)
                        pstr = tableCandWord->candWord.simpelRecord->strCode + FcitxInputStateGetRawInputBufferSize(input) -1 ;
                    else
                        pstr = tableCandWord->candWord.record->strCode + FcitxInputStateGetRawInputBufferSize(input) -1 ;
                }
                else {
                    if(tableCandWord->candWord.record->type == RECORDTYPE_S2T)
                        pstr = tableCandWord->candWord.simpelRecord->strCode + FcitxInputStateGetRawInputBufferSize(input) ;
                    else
                        pstr = tableCandWord->candWord.record->strCode + FcitxInputStateGetRawInputBufferSize(input);
                }
            } 
            else if(tableCandWord->candWord.record->type == RECORDTYPE_UNCOMMON && FcitxInputStateGetRawInputBuffer(input)[0] == fwb->config.unCommonKey){
                if(tableCandWord->candWord.record->type == RECORDTYPE_S2T)
                    pstr = tableCandWord->candWord.simpelRecord->strCode + FcitxInputStateGetRawInputBufferSize(input) -1 ;
                else
                    pstr = tableCandWord->candWord.record->strCode + FcitxInputStateGetRawInputBufferSize(input)-1;   
//                 printf("22:%s\n",pstr);
            }
            else{
                if(tableCandWord->candWord.record->type == RECORDTYPE_S2T)
                    pstr = tableCandWord->candWord.simpelRecord->strCode + FcitxInputStateGetRawInputBufferSize(input);
                else                
                    pstr = tableCandWord->candWord.record->strCode + FcitxInputStateGetRawInputBufferSize(input);
            }
        }
        else if(tableCandWord->flag == CT_AUTOPHRASE)
            pstr = tableCandWord->candWord.autoPhrase->strCode + FcitxInputStateGetRawInputBufferSize(input);
        if (pstr) {
            if(pstrS2t)
                candWord.strExtra = fcitx_utils_malloc0(sizeof(char) * (strlen(pstr) + strlen(pstrS2t) + 7));
            else
                candWord.strExtra = fcitx_utils_malloc0(sizeof(char) * (strlen(pstr)  + 5));

            *candWord.strExtra = ':';
            if(isSingleS2t){
                strcat(candWord.strExtra,"(");
                strcat(candWord.strExtra,pstrS2t);
                strcat(candWord.strExtra,")");
            }
            if(isSinglePinyin)
                strcat(candWord.strExtra,"[");
            strcat(candWord.strExtra, pstr);
            if(isSinglePinyin)
                strcat(candWord.strExtra,"]");               
            candWord.extraType = MSG_CODE;
        }
        FcitxCandidateWordAppend(candList, &candWord);
    }
    utarray_clear(&candTemp);
    utarray_clear(&candWubi);
    utarray_clear(&candPinyin);
    
    utarray_done(&candWubi);
    utarray_done(&candPinyin);
    utarray_done(&candTemp);
    INPUT_RETURN_VALUE retVal = IRV_DISPLAY_CANDWORDS;
    if (FcitxCandidateWordGetCurrentWindowSize(candList) == 1) {  //如果只有一个候选词，则送到客户程序中
        FcitxCandidateWord* candWord = FcitxCandidateWordGetCurrentWindow(candList);
        if (candWord->owner == fwb) {
            TABLECANDWORD* tableCandWord = candWord->priv;
            char* strCodeInput = FcitxInputStateGetRawInputBuffer(input);
            if (tableCandWord->flag == CT_NORMAL ){
                if (!strcmp(tableCandWord->candWord.record->strCode,strCodeInput)|| 
                    (tableCandWord->candWord.record->type == RECORDTYPE_S2T &&!strcmp(tableCandWord->candWord.simpelRecord->strCode,strCodeInput)) ||
                        (strCodeInput[0] == fwb->config.unCommonKey&&!strcmp(tableCandWord->candWord.record->strCode,strCodeInput+1)) || 
                          ((strCodeInput[0] == fwb->config.unCommonKey && tableCandWord->candWord.record->type == RECORDTYPE_S2T&&!strcmp(tableCandWord->candWord.record->strCode,strCodeInput+1))))
                    retVal = FcitxCandidateWordChooseByIndex(candList, 0);
            }
            else if(tableCandWord->flag == CT_AUTOPHRASE){
                retVal = FcitxCandidateWordChooseByIndex(candList, 0);
            }
        }
    }

    if (FcitxInputStateGetRawInputBufferSize(input)) {
        FcitxMessagesSetMessageCount(FcitxInputStateGetPreedit(input), 0);
        FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, FcitxInputStateGetRawInputBuffer(input));
        FcitxInputStateSetCursorPos(input, strlen(FcitxInputStateGetRawInputBuffer(input)));
        FcitxCandidateWord* candWord = NULL;
        if ((candWord = FcitxCandidateWordGetFirst(candList))) {
            FcitxMessagesSetMessageCount(FcitxInputStateGetClientPreedit(input), 0);
            FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT, candWord->strWord);
            FcitxInputStateSetClientCursorPos(input, 0);
        }
        else {
            FcitxMessagesSetMessageCount(FcitxInputStateGetClientPreedit(input), 0);
            FcitxMessageType type = MSG_INPUT;
            FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetClientPreedit(input), type, FcitxInputStateGetRawInputBuffer(input));
            FcitxInputStateSetClientCursorPos(input, 0);
        }
    }
    return retVal;
}
boolean FreeWubiPhraseTips(void *arg){
    return true;
}
void SaveFreeWubiIM(void *arg){
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    TableMetaData* table = fwb->table;
    if (!table)
        return;
    SaveTableDict(table);
}
INPUT_RETURN_VALUE FreeWubiKeyBlocker(void* arg, FcitxKeySym sym, unsigned int state){
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
    TableMetaData* table = fwb->table;
    
    FcitxInstance *instance = table->owner->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);

    do {
        if (!FcitxHotkeyIsHotKeySimple(sym, state))
            break;
        FcitxCandidateWordList *cand_list;
        cand_list = FcitxInputStateGetCandidateList(input);
        if (FcitxCandidateWordPageCount(cand_list)) {
            FcitxCandidateWord *candWord;
            candWord = FcitxCandidateWordGetCurrentWindow(cand_list);
            if (candWord->owner != fwb)
                break;
            INPUT_RETURN_VALUE ret = FreeWubiGetCandWord(fwb, candWord);
            if (!(ret & IRV_FLAG_PENDING_COMMIT_STRING))
                break;
            FcitxInstanceCommitString(
                instance, FcitxInstanceGetCurrentIC(instance),
                FcitxInputStateGetOutputString(input));
        }
        FcitxInputStateSetRawInputBufferSize(input, 0);
        FcitxInputStateGetRawInputBuffer(input)[0] = '\0';
        FcitxInputStateSetIsInRemind(input, false);
        FcitxInstanceCleanInputWindow(instance);
        FcitxUIUpdateInputWindow(instance);
        return IRV_FLAG_FORWARD_KEY;
    } while (0);
    return FcitxStandardKeyBlocker(input, sym, state);
}
void FreewubiReLoadConfig(void *arg){
    Fcitxfreewubi *fwb = (Fcitxfreewubi *)arg;
//printf("rrrrrrrrrrrrrrrrrrrrrrrrrFreewubiReLoadConfig\n");
FcitxIM * cr_im = FcitxInstanceGetCurrentIM(fwb->owner);
//printf("ccccccccccccccc   current im :%s\n",cr_im->uniqueName );

if(strcmp(cr_im->uniqueName,"freewb") == 0)
	switchImState(fwb, IM_INTO_FREEWB);
else
	switchImState(fwb, IM_CLOSE_FREEWB);
    reloadFreewb(fwb);
}
boolean reloadFreewb(Fcitxfreewubi *fwb){
    LoadFreeWubiGlobalInfo(fwb);
    if(fwb->config.bBackUpTable){
        if(fwb->table)
            FreeTableDict(fwb->table);
        LoadTableDict(fwb->table);
        resetTableFlag(fwb);
        fwb->config.bUserWordChanged = 1;
    }
    if(fwb->config.bUserWordChanged){
        LoadUsrDict(fwb->table);
        fwb->config.bUserWordChanged = 0;
        resetUerWordFlag(fwb);
    }
    if(fwb->config.bQuickTableChanged){
        freeQucikTable(fwb->table);
        LoadQuickTable(fwb->table);
        resetQuickTableFlag(fwb);
    }
    LoadAutoEng(fwb->table);
    if(fwb->config.iImType>=3){
        //fwb->config.iImType = fwb->table->tableType;
        switchFreeIm(fwb,fwb->config.iImType);
    }
    else{
        fwb->table->tableType = fwb->config.iImType;
        switchFreeIm(fwb,fwb->table->tableType);        
    }
    
    setVKboard(fwb->config.strUsrKeyBoard,VKM_INPUT_USER_CHAR);
    setVKboard(fwb->config.strPuncKeyBoard,VKM_INPUT_USER_MARK);    
}
boolean LoadFreeWubiGlobalInfo(Fcitxfreewubi *fwb){
    char *path = getFreewbPath();
    char *configPath;        
    fcitx_utils_alloc_cat_str(configPath, path, "/config/","config.ini");
    FILE* fpg = fopen(configPath, "r");
#ifdef DEBUG
    FcitxLog(INFO, _("config.ini: %s\n"),configPath);
#endif    
    free(path);
    free(configPath);

    if (!fpg) {
        FcitxLog(ERROR, _("FreeWubi: open config.ini fail"));
        return false;
    }
    FcitxConfigFile *cgfile = FcitxConfigParseConfigFileFp(fpg, GetFreewubiGlobalConfigDesc());
    fclose(fpg);
    if (!cgfile) {
        FcitxLog(ERROR, _("FreeWubi: open fcitx-freewubi.desc fail"));
        return false;
    }
    FcitxfreewubiConfigConfigBind(&fwb->config, cgfile, GetFreewubiGlobalConfigDesc());
    freeWbConfigBindSync((FcitxGenericConfig*)&fwb->config);
    FreewbCTRL_ENTER[0].desc = NULL;
    FreewbCTRL_ENTER[0].state = FcitxKeyState_Ctrl;
    FreewbCTRL_ENTER[0].sym = FcitxKey_Return;
    FreewbCAPS_LOCK[0].desc = NULL;
    FreewbCAPS_LOCK[0].state = FcitxKeyState_None;
    FreewbCAPS_LOCK[0].sym = FcitxKey_Caps_Lock;    
    fwb->hkReverseCheckByClip[0].desc = NULL;
    fwb->hkReverseCheckByClip[0].state = FcitxKeyState_Ctrl_Alt;
    fwb->hkReverseCheckByClip[0].sym = fwb->config.hkReverseCheck[0].sym;
    fwb->hkTableAddPhraseByClip[0].desc = NULL;
    fwb->hkTableAddPhraseByClip[0].state = FcitxKeyState_Ctrl_Alt;
    fwb->hkTableAddPhraseByClip[0].sym = fwb->config.hkTableAddPhrase[0].sym;      
    return true;
}

void* FcitxfreewubiCreate(FcitxInstance *instance)
{
//	printf("aaaaaaaaaaaaaaaaaaaaa FcitxfreewubiCreate\n");
    Fcitxfreewubi *freewubi = fcitx_utils_new(Fcitxfreewubi);
    bindtextdomain("fcitx-freewubi", LOCALEDIR);
    freewubi->owner = instance;
    freeDbusInit(freewubi);
    int times = 0;
    while(isFreewbRuning()){
        exitFreewbPanel(freewubi);
        sleep(1);
        if(times++>5){
            FcitxLog(ERROR,_("can not exit pannel,please kill panel manually!(may execute 'killall FreeWB')"));
            return NULL;
        }
    }
    run_freewb_pannel();
//    sleep(5);
    InternalInit(freewubi);
    
    FcitxIMIFace iface;
    memset(&iface, 0, sizeof(FcitxIMIFace));
    iface.ResetIM = FreewubiResetStatus;
    iface.DoInput = DoFreeWubiIntput;
    iface.GetCandWords = FreeWubiGetCandWords;
    iface.PhraseTips = FreeWubiPhraseTips;
    iface.Save = SaveFreeWubiIM;
    iface.Init = FreewubiInit;
    iface.ReloadConfig = FreewubiReLoadConfig;
    iface.KeyBlocker = FreeWubiKeyBlocker;
//     iface.UpdateSurroundingText = FcitxfreewubiUpdateSurroundingText;
    iface.DoReleaseInput = DoFreeWubiReleaseIntput;
    iface.OnClose = FcitxfreewubiClose;
    FcitxInstanceRegisterIMv2(
        freewubi->owner,
        freewubi,
        "freewb",
        _("Freewb"),
        _("Freewb"),
        iface,
        10,
        "zh_CN"
    );
//     FcitxInstanceRegisterIM(
//         freewubi->owner,
//         freewubi,
//         "freewb",
//         _("Freewb"),
//         "freewubi",
//         FreewubiInit,
//         FreewubiResetStatus,
//         DoFreeWubiIntput,
//         FreeWubiGetCandWords,
//         FreeWubiPhraseTips,
//         SaveFreeWubiIM,
//         FreewubiReLoadConfig,
//         FreeWubiKeyBlocker,
//         1,
//         "zh_CN"
//     ); 
//     FcitxInstanceSwitchIMByName(instance,"sogoupinyin");
    reloadFreewb(freewubi);
    return freewubi;
}

void FcitxfreewubiDestroy(void *arg)
{
    Fcitxfreewubi *freewubi = (Fcitxfreewubi*)arg;
    exitFreewbPanel(freewubi);
    TableMetaDataFree(freewubi->table);
    free(freewubi);
}

void TableMetaDataFree(TableMetaData *table)
{
    if (!table)
        return;
    FreeTableDict(table);
    freeAutoPhrase(table);
    FcitxConfigFree(&table->config);
    free(table);
}
void sortCandwords(UT_array *arry1, UT_array *arry2, UT_array *result){
    TABLECANDWORD** pcand1 = (TABLECANDWORD**)utarray_front(arry1);
    TABLECANDWORD** pcand2 = (TABLECANDWORD**)utarray_front(arry2);
    
    while(pcand1&&pcand2){
        TABLECANDWORD* tableCandWord1 = *pcand1;
        TABLECANDWORD* tableCandWord2 = *pcand2;
        RECORD *re1;
        RECORD *re2;
        if(tableCandWord1->candWord.record->type == RECORDTYPE_S2T)
            re1 = tableCandWord1->candWord.simpelRecord;
        else
            re1 = tableCandWord1->candWord.record;
        if(tableCandWord2->candWord.record->type == RECORDTYPE_S2T)
            re2 = tableCandWord2->candWord.simpelRecord;
        else
            re2 = tableCandWord2->candWord.record;        
        if(strcmp(re1->strCode,re2->strCode)<=0){
            utarray_push_back(result, &tableCandWord1);
            pcand1 = (TABLECANDWORD**) utarray_next(arry1, pcand1);
        }
        else{
            utarray_push_back(result, &tableCandWord2);
            pcand2 = (TABLECANDWORD**) utarray_next(arry2, pcand2);            
        }
    }
    while(pcand1){
        TABLECANDWORD* tableCandWord1 = *pcand1;
        utarray_push_back(result, &tableCandWord1);
        pcand1 = (TABLECANDWORD**) utarray_next(arry1, pcand1);
    }
    while(pcand2){
        TABLECANDWORD* tableCandWord2 = *pcand2;
        utarray_push_back(result, &tableCandWord2);
        pcand2 = (TABLECANDWORD**) utarray_next(arry2, pcand2);         
    }
}
boolean freeDbusInit(Fcitxfreewubi *fwb){
    if(fwb->conn)
        fwb->conn = NULL;
    DBusError err;
    dbus_error_init(&err);
    fwb->conn = dbus_bus_get(DBUS_BUS_SESSION,&err);    
    if(dbus_error_is_set(&err)){
        FcitxLog(INFO, _("DBusError:%s"), err.message);
        dbus_error_free(&err);
    }
    
    return fwb->conn!=NULL;
}
inline DBusConnection *getFreeDbusConn(Fcitxfreewubi *fwb){
    return fwb->conn;
}
void InternalInit(Fcitxfreewubi* freewubi)
{
    LoadFreeWubiGlobalInfo(freewubi);
    if(!freewubi->table){
        freewubi->table = fcitx_utils_new(TableMetaData);
        freewubi->table->autoRecord = fcitx_utils_new(AUTORECORD);
        freewubi->table->autoRecord->recordIndex = 0;
        freewubi->table->autoPhrase = fcitx_utils_new(AUTOPHRASE);
        freewubi->table->insertPoint = freewubi->table->autoPhrase;
        freewubi->table->autoPhrase->next = NULL;
        freewubi->table->quickTable = fcitx_utils_new(QUCIK_TABLE);
        freewubi->table->quickTable->next = NULL;
        freewubi->table->autoEng = fcitx_utils_new(AUTO_ENG);
        freewubi->table->autoEng->next = NULL;
        
        freewubi->table->owner = freewubi;
        LoadTableDict(freewubi->table);
        freewubi->table->tableType = FREE_WUBI;
    }
    freewubi->bNeedMoveCur = false;
    freewubi->pLastCommitRecord = NULL;
    freewubi->bNotFirstStart = false;
//    freewubi->bSwichImSeccess = false;
    
}
int TableCreateAutoPhrase(TableMetaData* tableMetaData, int iCount)
{
    Fcitxfreewubi* fwb = tableMetaData->owner;
    FcitxInstance *instance = fwb->owner;
    FcitxInputState *input = FcitxInstanceGetInputState(instance);
    FcitxCandidateWordList *cand_list = FcitxInputStateGetCandidateList(input);
    int hasRepeatRecord = 0;
    char repeatIndex[5] = "1.";
    char  *strHZ = NULL;
    char  strCode[5] = {0};
    AUTOPHRASE *autoPhrase = tableMetaData->autoPhrase->next;
    short i, j;
    i = (iCount -3)<0 ? 0: (iCount -3);
    while(i<iCount){
        boolean bFindRepeat = false;
        RECORD *repeatRecord = NULL;
        if(strHZ){
            free(strHZ);
            strHZ = NULL;
        }
        strHZ = malloc(sizeof(char) * (UTF8_MAX_LENGTH+1) * (iCount - i));
        memset(strHZ,0,sizeof(char) * (UTF8_MAX_LENGTH+1) * (iCount - i));
        for(j=i;j<=iCount;j++){
            strcat(strHZ,tableMetaData->autoRecord->recordHZ[j%4].strHZ);
        }
        while(autoPhrase){
            if(strcmp(autoPhrase->strHZ,strHZ)==0){
                bFindRepeat = true;
                break;
            }
            autoPhrase = autoPhrase->next;
        }     
        repeatRecord = TableFindPhrase(tableMetaData->WubiDict,strHZ);
        if(repeatRecord||bFindRepeat){
            if(fwb->config.bRemindExistWords&&repeatRecord){
                hasRepeatRecord++;
                repeatIndex[0] = '0'+hasRepeatRecord;
                FcitxInstanceCleanInputWindowUp( instance);
                FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input),
                                                    MSG_INPUT, _("#已有词组:"));  
                FcitxInputStateSetShowCursor(input,true);
                FcitxInputStateSetCursorPos(input, strlen("#已有词组:"));
                
                FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetAuxDown(input),
                                                    MSG_INDEX,repeatIndex );  
                FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetAuxDown(input),
                                                    MSG_FIRSTCAND, repeatRecord->strHZ);  
                FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetAuxDown(input),
                                                    MSG_FIRSTCAND, repeatRecord->strCode);
            }
            i++;
            continue;
        }
        if(TableCalPhraseCode(tableMetaData->WubiDict,strHZ,strCode)){
            tableMetaData->insertPoint->next = fcitx_utils_new(AUTOPHRASE);
            tableMetaData->insertPoint->next->strCode = malloc(sizeof(char)*(strlen(strCode)+1));
            strcpy(tableMetaData->insertPoint->next->strCode,strCode);
            tableMetaData->insertPoint->next->strHZ = malloc(sizeof(char)*(strlen(strHZ)+1));
            strcpy(tableMetaData->insertPoint->next->strHZ,strHZ);
            tableMetaData->insertPoint->next->iSelected = false;
            tableMetaData->insertPoint = tableMetaData->insertPoint->next;
            tableMetaData->insertPoint->next = NULL;
        }
        i++;
    }

    free(strHZ);
    return hasRepeatRecord;
}
void freeAutoPhrase(TableMetaData* tableMetaData){
    AUTOPHRASE *autoPhrase = tableMetaData->autoPhrase->next;
    while(autoPhrase){
        free(autoPhrase->strCode);
        free(autoPhrase->strHZ);
        AUTOPHRASE *temp = autoPhrase;
        autoPhrase = autoPhrase->next;
        free(temp);
    }
    free(tableMetaData->autoPhrase);
}
int digitalNumberTrans(FcitxKeySym sym)
{
    char *digitalStr = "!@#$%^&*()";
    int number = 0;
    while(*digitalStr){
        number++;
        if(*digitalStr++ == sym)
            return number;
    }
    return 100;
}
void playSound(SoundType sType)
{
    if ( sType > SOUND_NUM )
    {
        return;
    }
    char cmd[128] = {0};
    sprintf( cmd, "aplay %s%s%s > /dev/null 2>&1 &", SOUND_FILE_PATH, "/", soundData[sType] );
    system( cmd );    
}
